package com.bluetooth.lib.client;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import com.bluetooth.lib.BluetoothUtil;
import com.bluetooth.lib.impl.ATRCallBack;
import com.bluetooth.lib.impl.BluetoothClientImpl;
import com.bluetooth.lib.impl.SendCallback;
import com.bluetooth.lib.util.DispatchUtil;
import com.bluetooth.lib.util.F;
import com.bluetooth.lib.util.HexUtil;
import com.bluetooth.lib.util.L;
import com.bluetooth.lib.util.Md5Util;
import com.bluetooth.lib.util.T;

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

/**
 * 蓝牙客户端
 * */
@SuppressLint("NewApi")
public class BluetoothClient implements BluetoothClientImpl {
	private String tag = "BluetoothClient";

	private Context context;
	private BluetoothAdapter mBluetoothAdapter;
	private InnerReceiver mReceiver;
	private SearchCallBack searchCallBack;

	private List<BluetoothDevice> findDevices = new ArrayList<BluetoothDevice>();
	private SendThread sendThread;
	private volatile boolean threadRuning = false;
	private volatile boolean isstop = true;
	private SendUTFCallBack sendUTFCallBack;
	private volatile boolean isconnectSucess = false;
	DispatchMsg dispatchMsg = new DispatchMsg();
	private String waitLock = "";
	private ATRCallBack atrCallBack;
	private Handler mianHandler = new Handler() {
		public void dispatchMessage(Message msg) {
			dispatchMsg = (DispatchMsg) msg.obj;

			if (dispatchMsg.cmd.toUpperCase().equals("FEFEF801")) {
				if (atrCallBack != null) {
					atrCallBack.onATR(dispatchMsg.datelenght, dispatchMsg.data);
				}

			} else {
				if (sendUTFCallBack != null) {
					sendUTFCallBack.onReceive(dispatchMsg);
				}

			}

		};
	};

	private ConnectCallBack connectCallBack;

	public BluetoothClient(Context context) {
		this.context = context;
		initBlueTooth();
	}

	/**
	 * 初始化蓝牙设备
	 * */
	private void initBlueTooth() {
		mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
		if (mBluetoothAdapter == null) {
			Toast.makeText(context, "未获取到蓝牙适配器", 1000).show();
			return;
		}
		if (!mBluetoothAdapter.isEnabled()) {
			// 不做提示，强行打开
			mBluetoothAdapter.enable();
		}
		// 设置蓝牙可见
//		Intent enable = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
//		enable.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,
//				BluetoothUtil.DISCOVERABLE_TIME);
//		context.startActivity(enable);

		mReceiver = new InnerReceiver();
		IntentFilter filter = new IntentFilter();
		filter.addAction(BluetoothDevice.ACTION_FOUND);
		filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
		filter.setPriority(Integer.MAX_VALUE);
		context.registerReceiver(mReceiver, filter);
		
	}

	/**
	 * 搜索蓝牙设备
	 * */
	@Override
	public void search(SearchCallBack call) {
		findDevices.clear();
		this.searchCallBack = call;
		mBluetoothAdapter.startDiscovery();
	}

	/**
	 * 停止搜索
	 * */
	public void stopSearch() {
		if (mBluetoothAdapter != null)
			mBluetoothAdapter.cancelDiscovery();
	}

	/**
	 * 配对 可能会弹框
	 * */
	@SuppressLint("NewApi")
	public void createBond(BluetoothDevice device) {
		if (device != null)
			device.createBond();
	}

	/**
	 * 判断设备是否已配对
	 * */
	@SuppressLint("NewApi")
	public boolean isBonded(BluetoothDevice device) {
		if (device.getBondState() == BluetoothDevice.BOND_BONDED) {
			return true;
		}
		return false;
	}

	/**
	 * 连接指定设备
	 * */
	@SuppressLint("NewApi")
	@Override
	public void connect(BluetoothDevice device, ConnectCallBack call) {
		this.connectCallBack = call;
		L.i(tag, "连接 " + device.getName());
		mBluetoothAdapter.cancelDiscovery();
		if (!isBonded(device)) {
			createBond(device);
			Toast.makeText(context, "设备未配对，请先配对", Toast.LENGTH_LONG).show();
			// return;
		}

		if (threadRuning) {// 先结束掉正在运行的线程
			sendThread.handler.sendEmptyMessage(SendThread.CLOSE_SOCKET);
			sendThread.handler.sendEmptyMessage(SendThread.QUIT_THREAD);
			L.i(tag, "先执行关闭操作，再结束掉上一个线程 ");
		}
		long start = System.currentTimeMillis();
		while (threadRuning) {
			long end = System.currentTimeMillis();
			long t = end - start;
			L.i(tag, "结束上一个线程的时间：" + t + "ms");
			if (t > 3000) {// 最多等3秒
				break;
			}
		}
		sendThread = new SendThread(device);
		sendThread.start();

	}

	public void setOnSendUTFCallBack(SendUTFCallBack callBack) {
		this.sendUTFCallBack = callBack;
	}

	public void setOnATRCallBack(ATRCallBack callBack) {
		this.atrCallBack = callBack;
	}

	/**
	 * 
	 * 获得链接状态
	 */
	public boolean getConnectState() {

		return isconnectSucess;
	}

	// /**
	// * 发送utf字符串
	// * 使用此方法时服务端的ListenUTFCallBack 的onReceive方法中应该返回null
	// * 此方法可连续发送数据不用重新调用connect(BluetoothDevice device)方法
	// * */
	// @Override
	// public void sendUTF(String msg){
	// sendUTF(msg, null);
	// }

	/**
	 * 发送utf字符串 call 不为null时服务端的ListenCallBack 的onRecvUTF方法中应该返回非null值
	 * */
	@Override
	public void sendUTF(String msg, SendUTFCallBack call) {
		if (TextUtils.isEmpty(msg)) {
			L.i(tag, "发送的字符串为空");
			return;
		}
		this.sendUTFCallBack = call;
		if (sendThread != null) {
			sendThread.handler.sendMessage(sendThread.handler.obtainMessage(
					SendThread.SEND_UTF, msg));
		} else {
			throw new IllegalStateException("sendThread 为 null");
		}
	}

	/**
	 * 发送byte[]
	 * */
	@Override
	public void sendData(byte[] data) {
		if (data == null || data.length < 1) {
			L.i("JonPage", "发送的data为null或空");
			return;
		}
		if (sendThread != null) {
			sendThread.handler.sendMessage(sendThread.handler.obtainMessage(
					SendThread.SEND_DATA, data));
		} else {
			throw new IllegalStateException("sendThread 为 null");
		}

	}

	public DispatchMsg sendDatabyWait(byte[] data) {
		if (data == null || data.length < 1) {
			L.i("JonPage", "发送的data为null或空");
			return null;
		}
		if (!isconnectSucess) {
			Toast.makeText(context, "蓝牙没有链接", 1000).show();
			return null;
		}
		if (sendThread != null) {
			sendThread.handler.sendMessage(sendThread.handler.obtainMessage(
					SendThread.SEND_DATA, data));
			try {
				synchronized (waitLock) {
					waitLock.wait();
				}
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				Log.d("JonPage", e.getMessage());
			}
		}
		return dispatchMsg;
	}

	/**
	 * 发送文件
	 * 
	 * @param breakpoint
	 *            true断点续传 false不使用断点续传
	 * */
	@Override
	public void sendFile(File file, boolean isbreak) {
		if (file.isDirectory()) {
			L.i(tag, "发送的文件是目录，不可以发送");
			return;
		}
		if (sendThread != null) {
			if (isbreak) {
				sendThread.handler.sendMessage(sendThread.handler
						.obtainMessage(SendThread.SEND_FILE, file));
			} else {
				sendThread.handler.sendMessage(sendThread.handler
						.obtainMessage(SendThread.SEND_FILE_NEW, file));
			}
		} else {
			throw new IllegalStateException("sendThread 为 null");
		}

	}

	/**
	 * 关闭socket和工作线程
	 * */
	@Override
	public void close() {
		context.unregisterReceiver(mReceiver);
		isconnectSucess = false;
		if (threadRuning) {// 先结束掉线程
			sendThread.handler.sendEmptyMessage(SendThread.CLOSE_SOCKET);
			sendThread.handler.sendEmptyMessage(SendThread.QUIT_THREAD);
		}

	}

	/**
	 * 发送消息的线程
	 * */
	private class SendThread extends Thread {
		private Handler handler;
		private BluetoothDevice device;
		private BluetoothSocket socket;
		public static final int QUIT_THREAD = 0x21;
		public static final int CLOSE_SOCKET = 0x22;
		public static final int CONNECT = 0x23;
		public static final int SEND_UTF = 0x24;
		public static final int SEND_DATA = 0x25;
		public static final int SEND_FILE = 0x26;
		public static final int SEND_FILE_NEW = 0x27;// 不使用断点续传

		public SendThread(BluetoothDevice device) {
			this.device = device;

		}

		@Override
		public void run() {
			Looper.prepare();
			L.i(tag, "线程开始运行");
			threadRuning = true;
			handler = new Handler() {
				@Override
				public void handleMessage(Message msg) {
					switch (msg.what) {
					case QUIT_THREAD:
						Looper.myLooper().quit();
						break;
					case CONNECT:
						connect();
						break;
					case SEND_UTF:
						sendUTF((String) msg.obj);
						break;
					case SEND_DATA:
						sendData((byte[]) msg.obj);
						break;
					case SEND_FILE:// 断点续传
						sendFile((File) msg.obj, true);
						break;
					case SEND_FILE_NEW:// 非断点续传
						sendFile((File) msg.obj, false);
						break;
					case CLOSE_SOCKET:
						closeSocket();
						break;

					default:
						break;
					}

				}
			};
			connect();
			Looper.loop();
			threadRuning = false;

		}

		private void connect() {
			if (device == null)
				throw new IllegalStateException("device 为 null");
			try {
				L.i(tag, "创建socket");
				if (BluetoothUtil.SOCKET_TYPE == 1) {
					socket = device.createRfcommSocketToServiceRecord(UUID
							.fromString(BluetoothUtil.UUID));
				} else {
					socket = device
							.createInsecureRfcommSocketToServiceRecord(UUID
									.fromString(BluetoothUtil.UUID));
				}
				L.i(tag, "请求连接蓝牙设备");
				long start = System.currentTimeMillis();
				// if(socket.isConnected())
				// device.
				// socket.
				if (connectCallBack != null)
					connectCallBack.onStart();
				socket.connect();
				isconnectSucess = true;
				long end = System.currentTimeMillis();
				long t = end - start;
				if (connectCallBack != null && socket.isConnected()) {
					connectCallBack.onSuccess(t);
				}
				L.i(tag, "连接到蓝牙设备,用时：" + t + "ms");
				isstop = false;
				new Thread() {
					@Override
					public void run() {
						// TODO Auto-generated method stub
						super.run();
						onrecive();
					}
				}.start();
			} catch (Exception e) {
				L.i(tag, "出现异常：" + e.getMessage());
				e.printStackTrace();
				isconnectSucess = false;
				connectCallBack.onFail(e.getMessage());

			}
		}

		private void onrecive() {
			StringBuffer sb = new StringBuffer();
			int recLen = 0;
			while (!isstop) {
				try {
					InputStream input = socket.getInputStream();
					int count = 0;
					while (count == 0) {
						count = input.available();
					}
					byte[] data = new byte[count];
					recLen = input.read(data);
					if (recLen == 0) {
						continue;
					}

					sb.append(HexUtil.bytesToHex(data));
					dispatchMsg = DispatchUtil.dispatch(sb.toString());
					Log.d("JonPage", "接收数据ret:" + sb.toString());
					if (dispatchMsg != null) {
						if (dispatchMsg.isreciveover) { // 是否接收完成
							//Log.d("JonPage", "接收完成ret:" + dispatchMsg.cmd+HexUtil.IntToByteOneHex(dispatchMsg.datelenght)+dispatchMsg.data);
							synchronized (waitLock) {
								waitLock.notify();
							}
							Message message = new Message();
							message.obj = dispatchMsg;
							mianHandler.sendMessage(message);
							sb.delete(0, sb.length());
						}
					}

				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					L.i(tag, "接收出现异常：" + e.getMessage());
					sb.delete(0, sb.length());
				}
			}
		}

		private void sendUTF(String s) {
			L.i(tag, "发送：" + s);
			try {
				DataInputStream dis = new DataInputStream(
						socket.getInputStream());
				DataOutputStream dos = new DataOutputStream(
						socket.getOutputStream());
				// 发送数据类型
				dos.writeInt(BluetoothUtil.SEND_TYPE_UTF);
				dos.writeUTF(s);

			} catch (Exception e) {
				L.i(tag, "出现异常：" + e.getMessage());
				e.printStackTrace();
			}
		}

		private void sendData(byte[] data) {
			L.i("JonPage", "发送数据长度：" + data.length);
			try {
				Log.d("JonPage", "sendData" + HexUtil.bytesToHex(data));
				OutputStream out = socket.getOutputStream();
				out.write(data);
				out.flush();

			} catch (Exception e) {
				L.i(tag, "出现异常：" + e.getMessage());
				e.printStackTrace();
			}
		}

		private void closeSocket() {
			try {
				if (socket != null)
					socket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}

	/**
	 * 广播接收器
	 * */
	private class InnerReceiver extends BroadcastReceiver {
		@Override
		public void onReceive(Context context, Intent intent) {

			String action = intent.getAction();
			// 找到设备
			if (BluetoothDevice.ACTION_FOUND.equals(action)) {
				BluetoothDevice device = intent
						.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
				if (searchCallBack != null)
					searchCallBack.onSearching(device);
				findDevices.add(device);
			} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED
					.equals(action)) {
				// 搜索完成
				if (searchCallBack != null)
					searchCallBack.onSearchFinished(findDevices);
			}

		}

	}

	/**
	 * 搜索设备的callback
	 * */
	public interface SearchCallBack {

		void onSearching(BluetoothDevice device);

		void onSearchFinished(List<BluetoothDevice> devices);
	}

	/**
	 * 连接的回调
	 * */
	public interface ConnectCallBack {
		void onStart();

		void onSuccess(long times);

		void onFail(String s);
	}

	/**
	 * 发送消息的回调
	 * */
	public interface SendUTFCallBack {
		void onReceive(DispatchMsg dispatchMsg);
	}

}
